package com.gw.booking.util;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class TemplateUtil {
    private static final Logger logger = LoggerFactory.getLogger(TemplateUtil.class);
    private static final Pattern PATTERN_TEMPLATE = Pattern.compile("\\{\\$(\\w+)\\}");
    private static final Pattern PATTERN_OPT_TEMPLATE = Pattern.compile("\\{(\\w+)\\}");
    private static final Pattern PATTERN_OPTIONAL = Pattern.compile("\\[[^\\[\\]]+\\]");
    private static final Pattern PATTERN_OPT_TAG = Pattern.compile(":(\\w+)");
    private static final Map<String, Object> EMPTY_PARAM = new HashMap(1);

    private TemplateUtil() {
    }

    public static String replaceTemplate(String tplTxt, Map<String, ?> param, boolean replaceWithEmpty) {
        return replaceTemplate(tplTxt, PATTERN_TEMPLATE, param, replaceWithEmpty);
    }

    public static String replaceTemplate(String tplTxt, Pattern pattern, Map<String, ?> param, boolean replaceWithEmpty) {
        if (logger.isDebugEnabled()) {
            logger.debug("Tpl. Text=" + tplTxt + ", Param=" + param + ", ReplaceWithEmpty" + replaceWithEmpty);
        }

        if (param == null) {
            param = EMPTY_PARAM;
        }

        String ret = tplTxt;
        Matcher matcher = pattern.matcher(tplTxt);
        if (matcher.find()) {
            StringBuffer buff = new StringBuffer(tplTxt.length());

            do {
                String tagName = matcher.group(1);
                Object tagValue = param.get(tagName);
                String tagSection = matcher.group();
                if (tagValue == null) {
                    matcher.appendReplacement(buff, "");
                    if (!replaceWithEmpty) {
                        buff.append(tagSection);
                    }
                } else {
                    matcher.appendReplacement(buff, String.valueOf(tagValue));
                }
            } while(matcher.find());

            matcher.appendTail(buff);
            ret = buff.toString();
        }

        if (logger.isDebugEnabled()) {
            logger.debug("Return=" + ret);
        }

        return ret;
    }

    public static List<String> fixParamForCompileSql(String tplTxt, Map<String, ?> param) {
        if (logger.isDebugEnabled()) {
            logger.debug("Tpl. Text=" + tplTxt + ", Param=" + param);
        }

        if (param == null) {
            param = EMPTY_PARAM;
        }

        List<String> fixedList = new ArrayList();
        Matcher matcher = PATTERN_OPT_TAG.matcher(tplTxt);
        if (matcher.find()) {
            StringBuffer buff = new StringBuffer(tplTxt.length());

            do {
                String tagName = matcher.group(1);
                Object tagValue = param.get(tagName);
                if (tagValue == null) {
                    matcher.appendReplacement(buff, "");
                } else {
                    fixedList.add(tagName);
                }
            } while(matcher.find());
        }

        if (logger.isDebugEnabled()) {
            logger.debug("Return=" + tplTxt);
        }

        return fixedList;
    }

    public static String replaceTemplate(String tplTxt, Map<String, ?> param) {
        return replaceTemplate(tplTxt, param, true);
    }

    public static String removeOptionalFrag(String tplTxt, Map<String, ?> param, boolean findAll, boolean ignoreNoTag) {
        if (logger.isDebugEnabled()) {
            logger.debug("Tpl. Text=" + tplTxt + ", Param=" + param + ", FindAll=" + findAll + ", IgnoreNoTag" + ignoreNoTag);
        }

        if (param == null) {
            param = EMPTY_PARAM;
        }

        String ret = tplTxt;
        Matcher optMatcher = PATTERN_OPTIONAL.matcher(tplTxt);
        StringBuffer buff;
        String fragment;
        Matcher fragMatcher;
        int count;
        int found;
        String tagName;
        Object tagValue;
        if (optMatcher.find()) {
            buff = new StringBuffer(tplTxt.length());

            label125:
            do {
                fragment = optMatcher.group();
                fragMatcher = PATTERN_OPT_TAG.matcher(fragment);
                if (!fragMatcher.find()) {
                    if (ignoreNoTag) {
                        optMatcher.appendReplacement(buff, fragment);
                    } else {
                        optMatcher.appendReplacement(buff, fragment.substring(1, fragment.length() - 1));
                    }
                } else {
                    count = 0;
                    found = 0;

                    do {
                        tagName = fragMatcher.group(1);
                        tagValue = param.get(tagName);
                        if (tagValue != null && !StringUtils.isEmpty(tagValue.toString())) {
                            if (!findAll) {
                                optMatcher.appendReplacement(buff, fragment);
                                continue label125;
                            }

                            ++found;
                        } else if (findAll) {
                            optMatcher.appendReplacement(buff, "");
                            continue label125;
                        }

                        ++count;
                    } while(fragMatcher.find());

                    if ((!findAll || count != found) && (findAll || found == 0)) {
                        optMatcher.appendReplacement(buff, "");
                    } else {
                        optMatcher.appendReplacement(buff, fragment.substring(1, fragment.length() - 1));
                    }
                }
            } while(optMatcher.find());

            optMatcher.appendTail(buff);
            ret = buff.toString();
        }

        optMatcher = PATTERN_OPTIONAL.matcher(ret);
        if (optMatcher.find()) {
            buff = new StringBuffer(ret.length());

            labe173:
            do {
                fragment = optMatcher.group();
                fragMatcher = PATTERN_OPT_TEMPLATE.matcher(fragment);
                if (!fragMatcher.find()) {
                    if (ignoreNoTag) {
                        optMatcher.appendReplacement(buff, fragment);
                    } else {
                        optMatcher.appendReplacement(buff, fragment.substring(1, fragment.length() - 1));
                    }
                } else {
                    count = 0;
                    found = 0;

                    do {
                        tagName = fragMatcher.group(1);
                        tagValue = param.get(tagName);
                        if (tagValue != null && !StringUtils.isEmpty(tagValue.toString())) {
                            String s = fragment.substring(1, fragMatcher.start()) + String.valueOf(tagValue) + fragment.substring(fragMatcher.end(), fragment.length() - 1);
                            optMatcher.appendReplacement(buff, s);
                            if (!findAll) {
                                continue labe173;
                            }

                            ++found;
                        } else if (findAll) {
                            optMatcher.appendReplacement(buff, "");
                            continue labe173;
                        }

                        ++count;
                    } while(fragMatcher.find());

                    if ((!findAll || count != found) && (findAll || found == 0)) {
                        optMatcher.appendReplacement(buff, "");
                    }
                }
            } while(optMatcher.find());

            optMatcher.appendTail(buff);
            ret = buff.toString();
        }

        if (logger.isDebugEnabled()) {
            logger.debug("Return=" + ret);
        }

        return ret;
    }

    public static String removeOptionalFrag(String tplTxt, Map<String, ?> param) {
        return removeOptionalFrag(tplTxt, param, true, true);
    }
}
